﻿using System;
using System.Linq;
#if SILVERLIGHT
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Input;
using System.ComponentModel;
using System.Windows.Threading;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using Windows.UI.Xaml.Input;
#endif

namespace Microsoft.PlayerFramework
{
    [TemplatePart(Name = ControlPanelTemplateParts.ControlPanelElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = ControlPanelTemplateParts.LeftItemsPanelElement, Type = typeof(Panel))]
    [TemplatePart(Name = ControlPanelTemplateParts.LeftMarginElement, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = ControlPanelTemplateParts.ReplayButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.RewindButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.PlayPauseButtonElement, Type = typeof(ToggleButton))]
    [TemplatePart(Name = ControlPanelTemplateParts.StopButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.FastForwardButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.SlowMotionButtonElement, Type = typeof(ToggleButton))]
    [TemplatePart(Name = ControlPanelTemplateParts.SkipBackButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.SkipPreviousButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.ProgressTimeElement, Type = typeof(TextBlock))]
    [TemplatePart(Name = ControlPanelTemplateParts.MediaSliderGridElement, Type = typeof(Panel))]
    [TemplatePart(Name = ControlPanelTemplateParts.BufferingProgressBarElement, Type = typeof(ProgressBar))]
    [TemplatePart(Name = ControlPanelTemplateParts.DownloadProgressBarElement, Type = typeof(ProgressBar))]
    [TemplatePart(Name = ControlPanelTemplateParts.ProgressSliderElement, Type = typeof(SeekableSlider))]
    [TemplatePart(Name = ControlPanelTemplateParts.RightItemsPanelElement, Type = typeof(Panel))]
    [TemplatePart(Name = ControlPanelTemplateParts.SkipNextButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.SkipAheadButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.TotalMediaTimeElement, Type = typeof(TextBlock))]
    [TemplatePart(Name = ControlPanelTemplateParts.TotalTimeRemainingElement, Type = typeof(TextBlock))]
    [TemplatePart(Name = ControlPanelTemplateParts.CaptionsButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.AudioSelectorElement, Type = typeof(Selector))]
    [TemplatePart(Name = ControlPanelTemplateParts.VolumePanelElement, Type = typeof(Panel))]
    [TemplatePart(Name = ControlPanelTemplateParts.VerticalVolumeSliderGridElement, Type = typeof(Panel))]
    [TemplatePart(Name = ControlPanelTemplateParts.VerticalVolumeSliderElement, Type = typeof(Slider))]
    [TemplatePart(Name = ControlPanelTemplateParts.VolumeButtonElement, Type = typeof(ToggleButton))]
    [TemplatePart(Name = ControlPanelTemplateParts.VolumeSliderButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.AudioMuteButtonElement, Type = typeof(ToggleButton))]
    [TemplatePart(Name = ControlPanelTemplateParts.HorizontalVolumeSliderElement, Type = typeof(Slider))]
    [TemplatePart(Name = ControlPanelTemplateParts.FullScreenButtonElement, Type = typeof(ToggleButton))]
    [TemplatePart(Name = ControlPanelTemplateParts.GoLiveButtonElement, Type = typeof(ButtonBase))]
    [TemplatePart(Name = ControlPanelTemplateParts.SignalStrengthElement, Type = typeof(FrameworkElement))]
#if SILVERLIGHT
    [TemplatePart(Name = ControlPanelTemplateParts.DisplayModeButtonElement, Type = typeof(ButtonBase))]
#endif
    [TemplateVisualState(Name = ControlPanelVisualStates.LayoutStates.Normal, GroupName = ControlPanelVisualStates.GroupNames.LayoutStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.LayoutStates.Compact, GroupName = ControlPanelVisualStates.GroupNames.LayoutStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaStates.Buffering, GroupName = ControlPanelVisualStates.GroupNames.MediaStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaStates.Closed, GroupName = ControlPanelVisualStates.GroupNames.MediaStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaStates.Opening, GroupName = ControlPanelVisualStates.GroupNames.MediaStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaStates.Paused, GroupName = ControlPanelVisualStates.GroupNames.MediaStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaStates.Playing, GroupName = ControlPanelVisualStates.GroupNames.MediaStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaTypeStates.Audio, GroupName = ControlPanelVisualStates.GroupNames.MediaTypeStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.MediaTypeStates.Video, GroupName = ControlPanelVisualStates.GroupNames.MediaTypeStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.VerticalVolumeVisibilityStates.Dismissed, GroupName = ControlPanelVisualStates.GroupNames.VerticalVolumeVisibilityStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.VerticalVolumeVisibilityStates.Hidden, GroupName = ControlPanelVisualStates.GroupNames.VerticalVolumeVisibilityStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.VerticalVolumeVisibilityStates.Requested, GroupName = ControlPanelVisualStates.GroupNames.VerticalVolumeVisibilityStates)]
    [TemplateVisualState(Name = ControlPanelVisualStates.VerticalVolumeVisibilityStates.Visible, GroupName = ControlPanelVisualStates.GroupNames.VerticalVolumeVisibilityStates)]
    public partial class ControlPanel
    {
        #region Initialization

        const int MinTimelineWidth = 100;

        /// <summary>
        /// The left panel where all the controls before the timeline are placed.
        /// </summary>
        public Panel LeftItemsPanel { get; private set; }
        /// <summary>
        /// The panel that contains all controls to the right of the timeline.
        /// </summary>
        public Panel RightItemsPanel { get; private set; }
        /// <summary>
        /// The main panel element containing the controls.
        /// </summary>
        protected FrameworkElement ControlPanelElement { get; private set; }
        /// <summary>
        /// The left panel adding a margin before the first control.
        /// </summary>
        protected FrameworkElement LeftMarginElement { get; private set; }
        /// <summary>
        /// The replay (instant replay) button.
        /// </summary>
        protected ButtonBase ReplayButtonElement { get; private set; }
        /// <summary>
        /// The rewind/reverse button.
        /// </summary>
        protected ButtonBase RewindButtonElement { get; private set; }
        /// <summary>
        /// The play and pause toggle button.
        /// </summary>
        protected ToggleButton PlayPauseButtonElement { get; private set; }
        /// <summary>
        /// The stop button.
        /// </summary>
        protected ButtonBase StopButtonElement { get; private set; }
        /// <summary>
        /// The fast forward button.
        /// </summary>
        protected ButtonBase FastForwardButtonElement { get; private set; }
        /// <summary>
        /// The slow motion button.
        /// </summary>
        protected ToggleButton SlowMotionButtonElement { get; private set; }
        /// <summary>
        /// The skip back button (sends the user back 30 seconds in the timeline).
        /// </summary>
        protected ButtonBase SkipBackButtonElement { get; private set; }
        /// <summary>
        /// The skip previous button (sends the user to the previous marker).
        /// </summary>
        protected ButtonBase SkipPreviousButtonElement { get; private set; }
        /// <summary>
        /// The text that shows the current position.
        /// </summary>
        protected TextBlock ProgressTimeElement { get; private set; }
        /// <summary>
        /// The panel that contains the timeline.
        /// </summary>
        protected Panel MediaSliderGridElement { get; private set; }
        /// <summary>
        /// The buffering progress bar.
        /// </summary>
        protected ProgressBar BufferingProgressBarElement { get; private set; }
        /// <summary>
        /// The download progress bar for non-adaptive video.
        /// </summary>
        protected ProgressBar DownloadProgressBarElement { get; private set; }
        /// <summary>
        /// The timeline.
        /// </summary>
        protected SeekableSlider ProgressSliderElement { get; private set; }
        /// <summary>
        /// The skip next button. Sends the user to the next marker.
        /// </summary>
        protected ButtonBase SkipNextButtonElement { get; private set; }
        /// <summary>
        /// The skip ahead button. Sends user 30 seconds ahead in the timeline.
        /// </summary>
        protected ButtonBase SkipAheadButtonElement { get; private set; }
        /// <summary>
        /// The total duration of the media. This is usually mutually exclusive from the TotalTimeRemaining.
        /// </summary>
        protected TextBlock TotalMediaTimeElement { get; private set; }
        /// <summary>
        /// The time remaining in the media. This is usually mutually exclusive from the TotalMediaTime.
        /// </summary>
        protected TextBlock TotalTimeRemainingElement { get; private set; }
        /// <summary>
        /// The Captions button.
        /// </summary>
        protected ButtonBase CaptionsButtonElement { get; private set; }
        /// <summary>
        /// The ComboBox to allow you to select an audio track.
        /// </summary>
        protected Selector AudioSelectorElement { get; private set; }
        /// <summary>
        /// The volume panel that contains the mute and volume slider (used for audio and video media).
        /// </summary>
        protected Panel VolumePanelElement { get; private set; }
        /// <summary>
        /// The vertical volume slider panel (used for video media).
        /// </summary>
        protected Panel VerticalVolumeSliderGridElement { get; private set; }
        /// <summary>
        /// The vertical volume slider control (used for video media).
        /// </summary>
        protected Slider VerticalVolumeSliderElement { get; private set; }
        /// <summary>
        /// The mute and volume slider toggle button (used for video media).
        /// </summary>
        protected ToggleButton VolumeButtonElement { get; private set; }
        /// <summary>
        /// The button that only invokes the vertical flyout without toggling mute (used for video media).
        /// </summary>
        protected ButtonBase VolumeSliderButtonElement { get; private set; }
        /// <summary>
        /// The mute toggle button (used for audio media).
        /// </summary>
        protected ToggleButton AudioMuteButtonElement { get; private set; }
        /// <summary>
        /// The horizontal volume slider (used for audio media where you can't extend vertically).
        /// </summary>
        protected Slider HorizontalVolumeSliderElement { get; private set; }
        /// <summary>
        /// The fullscreen toggle button.
        /// </summary>
        protected ToggleButton FullScreenButtonElement { get; private set; }
        /// <summary>
        /// The go live button.
        /// </summary>
        protected ButtonBase GoLiveButtonElement { get; private set; }
        /// <summary>
        /// The signal strength indicator (usually adaptive only).
        /// </summary>
        protected FrameworkElement SignalStrengthElement { get; private set; }

#if SILVERLIGHT
        /// <summary>
        /// The button to allow the user to cycle through display modes (Letterbox, stretch, native, ...etc).
        /// </summary>
        protected ButtonBase DisplayModeButtonElement { get; private set; }
#endif

        /// <inheritdoc /> 
        protected virtual void GetTemplateChildren()
        {
            ControlPanelElement = GetTemplateChild(ControlPanelTemplateParts.ControlPanelElement) as FrameworkElement;
            LeftItemsPanel = GetTemplateChild(ControlPanelTemplateParts.LeftItemsPanelElement) as Panel;
            LeftMarginElement = GetTemplateChild(ControlPanelTemplateParts.LeftMarginElement) as FrameworkElement;

            ReplayButtonElement = GetTemplateChild(ControlPanelTemplateParts.ReplayButtonElement) as ButtonBase;
            RewindButtonElement = GetTemplateChild(ControlPanelTemplateParts.RewindButtonElement) as ButtonBase;
            PlayPauseButtonElement = GetTemplateChild(ControlPanelTemplateParts.PlayPauseButtonElement) as ToggleButton;
            StopButtonElement = GetTemplateChild(ControlPanelTemplateParts.StopButtonElement) as ButtonBase;
            FastForwardButtonElement = GetTemplateChild(ControlPanelTemplateParts.FastForwardButtonElement) as ButtonBase;
            SlowMotionButtonElement = GetTemplateChild(ControlPanelTemplateParts.SlowMotionButtonElement) as ToggleButton;
            SkipBackButtonElement = GetTemplateChild(ControlPanelTemplateParts.SkipBackButtonElement) as ButtonBase;
            SkipPreviousButtonElement = GetTemplateChild(ControlPanelTemplateParts.SkipPreviousButtonElement) as ButtonBase;
            ProgressTimeElement = GetTemplateChild(ControlPanelTemplateParts.ProgressTimeElement) as TextBlock;

            MediaSliderGridElement = GetTemplateChild(ControlPanelTemplateParts.MediaSliderGridElement) as Panel;
            BufferingProgressBarElement = GetTemplateChild(ControlPanelTemplateParts.BufferingProgressBarElement) as ProgressBar;
            DownloadProgressBarElement = GetTemplateChild(ControlPanelTemplateParts.DownloadProgressBarElement) as ProgressBar;
            ProgressSliderElement = GetTemplateChild(ControlPanelTemplateParts.ProgressSliderElement) as SeekableSlider;

            RightItemsPanel = GetTemplateChild(ControlPanelTemplateParts.RightItemsPanelElement) as Panel;
            SkipNextButtonElement = GetTemplateChild(ControlPanelTemplateParts.SkipNextButtonElement) as ButtonBase;
            SkipAheadButtonElement = GetTemplateChild(ControlPanelTemplateParts.SkipAheadButtonElement) as ButtonBase;
            TotalMediaTimeElement = GetTemplateChild(ControlPanelTemplateParts.TotalMediaTimeElement) as TextBlock;
            TotalTimeRemainingElement = GetTemplateChild(ControlPanelTemplateParts.TotalTimeRemainingElement) as TextBlock;
            CaptionsButtonElement = GetTemplateChild(ControlPanelTemplateParts.CaptionsButtonElement) as ButtonBase;
            AudioSelectorElement = GetTemplateChild(ControlPanelTemplateParts.AudioSelectorElement) as Selector;

            VolumePanelElement = GetTemplateChild(ControlPanelTemplateParts.VolumePanelElement) as Panel;
            VerticalVolumeSliderGridElement = GetTemplateChild(ControlPanelTemplateParts.VerticalVolumeSliderGridElement) as Panel;
            VerticalVolumeSliderElement = GetTemplateChild(ControlPanelTemplateParts.VerticalVolumeSliderElement) as Slider;
            VolumeButtonElement = GetTemplateChild(ControlPanelTemplateParts.VolumeButtonElement) as ToggleButton;
            VolumeSliderButtonElement = GetTemplateChild(ControlPanelTemplateParts.VolumeSliderButtonElement) as ButtonBase;
            AudioMuteButtonElement = GetTemplateChild(ControlPanelTemplateParts.AudioMuteButtonElement) as ToggleButton;
            HorizontalVolumeSliderElement = GetTemplateChild(ControlPanelTemplateParts.HorizontalVolumeSliderElement) as Slider;

            FullScreenButtonElement = GetTemplateChild(ControlPanelTemplateParts.FullScreenButtonElement) as ToggleButton;
            GoLiveButtonElement = GetTemplateChild(ControlPanelTemplateParts.GoLiveButtonElement) as ButtonBase;
            SignalStrengthElement = GetTemplateChild(ControlPanelTemplateParts.SignalStrengthElement) as FrameworkElement;
#if SILVERLIGHT
            DisplayModeButtonElement = GetTemplateChild(ControlPanelTemplateParts.DisplayModeButtonElement) as ButtonBase;
#endif
        }

        void SetDefaultVisualStates()
        {
            UpdateAudioVideoVisualState();
            UpdateCurrentStateVisualState();
            UpdateVolumeVisualState();
            UpdateCompactVisualState();
        }

        private void UpdateAudioVideoVisualState()
        {
            this.GoToVisualState(ControlPanelVisualStates.MediaTypeStates.Video);
        }

        private void UpdateCompactVisualState()
        {
            if (IsCompact)
            {
                this.GoToVisualState(ControlPanelVisualStates.LayoutStates.Compact);
            }
            else
            {
                this.GoToVisualState(ControlPanelVisualStates.LayoutStates.Normal);
            }
        }

        private void UpdateVolumeVisualState()
        {
            if (IsVolumeVisible)
            {
                this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Visible);
            }
            else
            {
                this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Hidden);
            }
        }

        void InitializeTemplateChildren()
        {
            if (MediaSliderGridElement != null)
            {
                MediaSliderGridElement.SizeChanged += MediaSliderGridElement_SizeChanged;
            }
            if (ProgressSliderElement != null)
            {
                ProgressSliderElement.ScrubbingStarted += ProgressSliderElement_ScrubbingStarted;
                ProgressSliderElement.ScrubbingCompleted += ProgressSliderElement_ScrubbingCompleted;
                ProgressSliderElement.Scrubbing += ProgressSliderElement_Scrubbing;
            }
            if (VolumeButtonElement != null)
            {
                VolumeButtonElement.GotFocus += VolumeButtonElement_GotFocus;
                VolumeButtonElement.Click += VolumeButtonElement_Click;
            }
            if (VolumeSliderButtonElement != null)
            {
                VolumeSliderButtonElement.Click += VolumeButtonElement_Click;
            }

            if (VerticalVolumeSliderGridElement != null)
            {
#if SILVERLIGHT
                VerticalVolumeSliderGridElement.MouseMove += VerticalVolumeSliderGridElement_MouseMove;
                VerticalVolumeSliderGridElement.MouseLeftButtonDown += VerticalVolumeSliderGridElement_MouseLeftButtonDown;
#else
                VerticalVolumeSliderGridElement.PointerMoved += VerticalVolumeSliderGridElement_PointerMoved;
                VerticalVolumeSliderGridElement.PointerPressed += VerticalVolumeSliderGridElement_PointerPressed;
#endif
            }

            if (ViewModel != null)
            {
                InitializeViewModel(ViewModel);
            }

            volumeCollapseTimer.Tick += volumeCollapseTimer_Tick;
        }

        void UninitializeTemplateChildren()
        {
            if (MediaSliderGridElement != null)
            {
                MediaSliderGridElement.SizeChanged -= MediaSliderGridElement_SizeChanged;
            }
            if (ProgressSliderElement != null)
            {
                ProgressSliderElement.ScrubbingStarted -= ProgressSliderElement_ScrubbingStarted;
                ProgressSliderElement.ScrubbingCompleted -= ProgressSliderElement_ScrubbingCompleted;
                ProgressSliderElement.Scrubbing -= ProgressSliderElement_Scrubbing;
            }
            if (VolumeButtonElement != null)
            {
                VolumeButtonElement.GotFocus -= VolumeButtonElement_GotFocus;
                VolumeButtonElement.Click -= VolumeButtonElement_Click;
            }
            if (VolumeSliderButtonElement != null)
            {
                VolumeSliderButtonElement.Click -= VolumeButtonElement_Click;
            }

            if (VerticalVolumeSliderGridElement != null)
            {
#if SILVERLIGHT
                VerticalVolumeSliderGridElement.MouseMove -= VerticalVolumeSliderGridElement_MouseMove;
                VerticalVolumeSliderGridElement.MouseLeftButtonDown -= VerticalVolumeSliderGridElement_MouseLeftButtonDown;
#else
                VerticalVolumeSliderGridElement.PointerMoved -= VerticalVolumeSliderGridElement_PointerMoved;
                VerticalVolumeSliderGridElement.PointerPressed -= VerticalVolumeSliderGridElement_PointerPressed;
#endif
            }

            if (ViewModel != null)
            {
                UninitializeViewModel(ViewModel);
            }

            volumeCollapseTimer.Tick -= volumeCollapseTimer_Tick;
        }

        void InitializeViewModel(IInteractiveViewModel vm)
        {
            vm.CurrentStateChanged += ViewModel_CurrentStateChanged;

            // need to set these bindings in code; xaml doesn't like binding to the converter
            if (ProgressTimeElement != null)
            {
                ProgressTimeElement.SetBinding(TextBlock.TextProperty, new Binding() { Path = new PropertyPath("Position"), Source = vm, Converter = vm != null ? vm.TimeFormatConverter : null });
            }
            if (TotalMediaTimeElement != null)
            {
                TotalMediaTimeElement.SetBinding(TextBlock.TextProperty, new Binding() { Path = new PropertyPath("Duration"), Source = vm, Converter = vm != null ? vm.TimeFormatConverter : null });
            }
            if (TotalTimeRemainingElement != null)
            {
                TotalTimeRemainingElement.SetBinding(TextBlock.TextProperty, new Binding() { Path = new PropertyPath("TimeRemaining"), Source = vm, Converter = vm != null ? vm.TimeFormatConverter : null });
            }
        }

        void UninitializeViewModel(IInteractiveViewModel vm)
        {
            vm.CurrentStateChanged -= ViewModel_CurrentStateChanged;

            if (ProgressTimeElement != null)
            {
                ProgressTimeElement.SetBinding(TextBlock.TextProperty, new Binding());
            }
            if (TotalMediaTimeElement != null)
            {
                TotalMediaTimeElement.SetBinding(TextBlock.TextProperty, new Binding());
            }
            if (TotalTimeRemainingElement != null)
            {
                TotalTimeRemainingElement.SetBinding(TextBlock.TextProperty, new Binding());
            }
        }

        #endregion

        #region Element events

        double lastToggleWidth = 320;
        void MediaSliderGridElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (IsCompact && e.NewSize.Width > MinTimelineWidth && lastToggleWidth + 5 < this.ActualWidth)
            {
                Dispatcher.BeginInvoke(() => IsCompact = false);
            }
            else if (!IsCompact && e.NewSize.Width < MinTimelineWidth)
            {
                // don't pop into compact mode unless you reach the same point at which you entered
                lastToggleWidth = this.ActualWidth;
                Dispatcher.BeginInvoke(() => IsCompact = true);
            }
        }

        void ProgressSliderElement_Scrubbing(object sender, ValueRoutedEventArgs e)
        {
            if (ViewModel != null)
            {
                var vm = ViewModel; // hold onto this in case the ViewModel changes because of this action. This way we can ensure we're calling the same one.
                bool canceled = false;
                vm.Scrub(TimeSpan.FromSeconds(e.Value), out canceled);
                if (canceled)
                {
                    ProgressSliderElement.CancelScrub();
                    vm.CompleteScrub(TimeSpan.FromSeconds(e.Value), ref canceled);
                }
            }
        }

        void ProgressSliderElement_ScrubbingCompleted(object sender, ValueRoutedEventArgs e)
        {
            if (ViewModel != null)
            {
                bool canceled = false;
                ViewModel.CompleteScrub(TimeSpan.FromSeconds(e.Value), ref canceled);
            }
        }

        void ProgressSliderElement_ScrubbingStarted(object sender, ValueRoutedEventArgs e)
        {
            if (ViewModel != null)
            {
                var vm = ViewModel; // hold onto this in case the ViewModel changes because of this action. This way we can ensure we're calling the same one.
                bool canceled = false;
                vm.StartScrub(TimeSpan.FromSeconds(e.Value), out canceled);
                if (canceled)
                {
                    ProgressSliderElement.CancelScrub();
                    vm.CompleteScrub(TimeSpan.FromSeconds(e.Value), ref canceled);
                }
            }
        }

#if SILVERLIGHT
        void VerticalVolumeSliderGridElement_MouseMove(object sender, MouseEventArgs e)
#else
        void VerticalVolumeSliderGridElement_PointerMoved(object sender, PointerRoutedEventArgs e)
#endif
        {
            if (volumeCollapseTimer.IsEnabled) volumeCollapseTimer.Stop();
            volumeCollapseTimer.Start();
        }

#if SILVERLIGHT
        void VerticalVolumeSliderGridElement_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
#else
        void VerticalVolumeSliderGridElement_PointerPressed(object sender, PointerRoutedEventArgs e)
#endif
        {
            if (volumeCollapseTimer.IsEnabled) volumeCollapseTimer.Stop();
            volumeCollapseTimer.Start();
        }

        readonly DispatcherTimer volumeCollapseTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(3) };

        bool isVolumeVisible;
        /// <summary>
        /// Gets or sets whether the volume panel is visible.
        /// </summary>
        public bool IsVolumeVisible
        {
            get { return isVolumeVisible; }
            set
            {
                if (isVolumeVisible != value)
                {
                    isVolumeVisible = value;
                    if (isVolumeVisible)
                    {
                        volumeCollapseTimer.Start();
                    }
                    else
                    {
                        if (volumeCollapseTimer.IsEnabled) volumeCollapseTimer.Stop();
                    }
                }
            }
        }

#if SILVERLIGHT
        void volumeCollapseTimer_Tick(object sender, EventArgs e)
#else
        void volumeCollapseTimer_Tick(object sender, object e)
#endif
        {
            volumeCollapseTimer.Stop();
            IsVolumeVisible = false;
            this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Hidden);
        }

        void VolumeButtonElement_GotFocus(object sender, RoutedEventArgs e)
        {
#if !SILVERLIGHT
            if (VolumeButtonElement.FocusState == FocusState.Keyboard)
#endif
            {
                if (!IsVolumeVisible)
                {
                    this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Requested);
                    IsVolumeVisible = true;
                }
            }
        }

        void VolumeButtonElement_Click(object sender, RoutedEventArgs e)
        {
            if (!IsVolumeVisible)
            {
                this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Requested);
                IsVolumeVisible = true;
            }
            else
            {
                this.GoToVisualState(ControlPanelVisualStates.VerticalVolumeVisibilityStates.Dismissed);
                IsVolumeVisible = false;
            }
        }

        #endregion

        #region MediaPlayer Events

        void ViewModel_CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            UpdateCurrentStateVisualState();
        }

        private void UpdateCurrentStateVisualState()
        {
            if (ViewModel == null)
            {
                this.GoToVisualState(ControlPanelVisualStates.MediaStates.Closed);
            }
            else
            {
                switch (ViewModel.CurrentState)
                {
#if SILVERLIGHT
                    case MediaElementState.AcquiringLicense:
                    case MediaElementState.Individualizing:
#endif
                    case MediaElementState.Opening:
                        this.GoToVisualState(ControlPanelVisualStates.MediaStates.Opening);
                        break;
                    case MediaElementState.Buffering:
                        this.GoToVisualState(ControlPanelVisualStates.MediaStates.Buffering);
                        break;
                    case MediaElementState.Playing:
                        this.GoToVisualState(ControlPanelVisualStates.MediaStates.Playing);
                        break;
                    case MediaElementState.Closed:
                        this.GoToVisualState(ControlPanelVisualStates.MediaStates.Closed);
                        break;
                    case MediaElementState.Paused:
                    case MediaElementState.Stopped:
                        this.GoToVisualState(ControlPanelVisualStates.MediaStates.Paused);
                        break;
                }
            }
        }

        #endregion

        #region Properties

        bool isCompact;
        private bool IsCompact
        {
            get { return isCompact; }
            set
            {
                if (isCompact != value)
                {
                    isCompact = value;
                    UpdateCompactVisualState();
                }
            }
        }

        #endregion

    }
}
